using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using System.Diagnostics;

namespace MoEngine
{
    public delegate void UpdateEvent(GameTime gameTime);

    public abstract class State
    {
        protected BaseStateManager StateMgr;
        public virtual void Init(object host, BaseStateManager stateManager)
        {
            StateMgr = stateManager;        
        }

        public virtual void BeginState(State prevState) { }

        public virtual void EndState(State nextState) { }

        public virtual void Update(GameTime gameTime) { }

        public virtual void Goto(Type stateType)
        {
            StateMgr.GotoState(stateType);
        }
    }

    public abstract class BaseStateManager
    {
        public abstract void GotoState(Type stateType); 

    }

    public class StateManager<T> : BaseStateManager where T : State
    {
//        private object m_Host;

/*
        public State NewState(int stateId)
        {
            State new_state = new State();
            AddState(stateId, new_state);
            return new_state;
        }

        private List<State> m_States = new List<State>();

        public void AddState(int stateId, State state)
        {
            state.StateId = stateId;
            AddState(state);
        }*/

        private Dictionary<Type, T> m_States = new Dictionary<Type,T>();

        public void AddState(T state, object host)
        {
            state.Init(host, this);

            Debug.Assert(!m_States.ContainsKey(state.GetType()));

            m_States[state.GetType()] = state;

            /*
            if (state.StateId == m_States.Count)
            {
                m_States.Add(state);
            }
            else if (state.StateId > m_States.Count)
            {
                State[] emptyStates = new State[state.StateId + 1 - m_States.Count];
                m_States.AddRange(emptyStates);
                m_States[state.StateId] = state;
            }*/
        }

        public override void GotoState(Type stateType)
        {
            T prevState = m_CurrentState;
            T nextState = m_States[stateType];

            if (prevState != null)
                prevState.EndState(nextState);

            m_CurrentState = nextState;

            if (nextState != null)
            {
                nextState.BeginState(prevState);
            }
            else
            {
                // TODO: warn
            }
        }

        public T FindState(Type stateType)
        {
            T state;
            return m_States.TryGetValue(stateType, out state) ? state : null;
        }

        public StateType FindState<StateType>() where StateType : T
        {
            return FindState(typeof(StateType)) as StateType;
        }

        public void Update(GameTime gameTime)
        {
            if (CurrentState != null)
                CurrentState.Update(gameTime);
        }

        private T m_CurrentState = null;

        // todo: may want to cache it
        public T CurrentState
        {
            get { return m_CurrentState; }
        }

        public Type CurrentStateType
        {
            get { return m_CurrentState.GetType(); }
        }
    }
}
